﻿using RenderHeads.Media.AVProVideo;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Networking;
using UnityEngine.UI;

namespace BToolkit.ExeUtils
{
    [ExecuteInEditMode]
    [RequireComponent(typeof(MediaPlayer))]
    public class AVProPlayer : MonoBehaviour
    {
        [Header("不带后缀名")]
        public string fileName;
        [Space]
        public bool autoLoad = true;
        public bool canResize = true;
        public bool autoPlay = true;
        public bool playSound = true;
        public Color color = Color.white;
        public VideoController controller;
        [Space]
        public UnityEvent onLoaded;
        public UnityEvent onPlayEnd;
        public Action onLoadedAction, onPlayEndAction;

        internal RectTransform rectTransform { get { return transform as RectTransform; } }
        internal float radian;
        internal float radius;
        internal RawImage rawImage;
        internal DisplayUGUI displayUGUI;
        internal MediaPlayer mediaPlayer;
        internal string path;
        internal bool isLoaded { private set; get; }
        public bool isVideo { get { return mediaPlayer.enabled; } }
        Queue<Action> mainThreadActions = new Queue<Action>();

        void OnDestroy()
        {
            if (Application.isPlaying) DestroyAssets(false);
        }

        void DestroyAssets(bool destroyComponent = true)
        {
            //RawImage
            rawImage = GetComponent<RawImage>();
            if (rawImage)
            {
                if (rawImage.texture)
                {
                    if (rawImage.texture.GetType() == typeof(RenderTexture)) (rawImage.texture as RenderTexture).Release();
                    DestroyImmediate(rawImage.texture, true);
                }
                if (destroyComponent) DestroyImmediate(rawImage);
            }

            //DisplayUGUI
            displayUGUI = GetComponent<DisplayUGUI>();
            if (displayUGUI)
            {
                if (displayUGUI.mainTexture)
                {
                    if (displayUGUI.mainTexture.GetType() == typeof(RenderTexture)) (displayUGUI.mainTexture as RenderTexture).Release();
                    DestroyImmediate(displayUGUI.mainTexture, true);
                }
                if (destroyComponent) DestroyImmediate(displayUGUI);
            }
            Resources.UnloadUnusedAssets();
        }

        void Awake()
        {
            rawImage = GetComponent<RawImage>();
            if (rawImage && Application.isPlaying)
            {
                rawImage.color = color;
                rawImage.enabled = false;
            }
            mediaPlayer = GetComponent<MediaPlayer>();
            mediaPlayer.m_AutoOpen = false;
            mediaPlayer.m_AutoStart = false;
            mediaPlayer.PlatformOptionsWindows.useHardwareDecoding = Config.Instance.VideoHardwareDecode;
            mediaPlayer.Events.AddListener(OnVideoEvent);
            if (IsFullScreen())
            {
                canResize = false;
            }
        }

        void Start()
        {
            if (autoLoad && !string.IsNullOrEmpty(fileName) && Application.isPlaying)
            {
                LoadNoSuffixPath(MainController.resPath + "/" + fileName, canResize, autoPlay, playSound, null, true);
            }
        }

        private void OnVideoEvent(MediaPlayer player, MediaPlayerEvent.EventType eventType, ErrorCode errorCode)
        {
            switch (eventType)
            {
                case MediaPlayerEvent.EventType.FirstFrameReady:
                    isLoaded = true;
                    onLoadedAction?.Invoke();
                    onLoaded?.Invoke();
                    break;
                case MediaPlayerEvent.EventType.FinishedPlaying:
                    onPlayEndAction?.Invoke();
                    onPlayEnd?.Invoke();
                    break;
            }
        }

        private void Update()
        {
            while (mainThreadActions.Count > 0)
            {
                Action action = mainThreadActions.Dequeue();
                if (action != null)
                {
                    try
                    {
                        action();
                    }
                    catch { }
                }
            }

            if (Application.isEditor)
            {
#if UNITY_EDITOR
                if (autoLoad)
                {
                    rawImage = GetComponent<RawImage>();
                    if (rawImage && rawImage.texture)
                    {
                        string path = UnityEditor.AssetDatabase.GetAssetPath(rawImage.texture);
                        if (!string.IsNullOrEmpty(path))
                        {
                            int dotIndex = path.LastIndexOf('.');
                            path = path.Substring(0, dotIndex);
                            int resIndex = path.IndexOf("/Res/") + 5;
                            path = path.Substring(resIndex);
                            fileName = path;
                        }
                    }
                }
#endif
            }
        }

        public void LoadNoSuffixPath(string fullPathNoSuffix, bool canResize = true, bool autoPlay = true, bool playSound = true, Action onPlayEnd = null, bool isHideWhenLoadFailed = false)
        {
            gameObject.SetActive(true);
            this.canResize = IsFullScreen() ? false : canResize;
            if (onPlayEnd != null) this.onPlayEndAction = onPlayEnd;
            bool isLoop = onPlayEnd == null;
            fullPathNoSuffix = fullPathNoSuffix.Replace("\\", "/");
            if (File.Exists(fullPathNoSuffix + ".mp4"))
            {
                LoadAndPlayVideo(fullPathNoSuffix + ".mp4", autoPlay, playSound, isLoop);
                return;
            }
            else if (File.Exists(fullPathNoSuffix + ".mov"))
            {
                LoadAndPlayVideo(fullPathNoSuffix + ".mov", autoPlay, playSound, isLoop);
                return;
            }
            else if (File.Exists(fullPathNoSuffix + ".webm"))
            {
                LoadAndPlayVideo(fullPathNoSuffix + ".webm", autoPlay, playSound, isLoop);
                return;
            }
            else if (File.Exists(fullPathNoSuffix + ".png"))
            {
                LoadAndShowTexture(fullPathNoSuffix + ".png");
                return;
            }
            else if (File.Exists(fullPathNoSuffix + ".jpg"))
            {
                LoadAndShowTexture(fullPathNoSuffix + ".jpg");
                return;
            }
            if (isHideWhenLoadFailed)
            {
                //资源不存在则隐藏
                Debug.Log($"文件{fullPathNoSuffix}不存在");
                gameObject.SetActive(false);
            }
        }

        public void LoadByFullPath(string fullPath, bool canResize = true, bool autoPlay = true, bool playSound = true, Action onPlayEnd = null)
        {
            LoadByFullPath(fullPath, canResize, autoPlay, playSound, onPlayEnd, false);
        }

        public void LoadByFullPathAsync(string fullPath, bool canResize = true, bool autoPlay = true, bool playSound = true, Action onPlayEnd = null)
        {
            LoadByFullPath(fullPath, canResize, autoPlay, playSound, onPlayEnd, true);
        }

        void LoadByFullPath(string fullPath, bool canResize = true, bool autoPlay = true, bool playSound = true, Action onPlayEnd = null, bool useAsync = false)
        {
            gameObject.SetActive(true);
            this.path = fullPath;
            this.canResize = IsFullScreen() ? false : canResize;
            if (onPlayEnd != null) this.onPlayEndAction = onPlayEnd;
            fullPath = fullPath.Replace("\\", "/");
            bool isLoop = onPlayEnd == null;
            if (fullPath.ToLower().EndsWith(".jpg") || fullPath.ToLower().EndsWith(".png"))
            {
                if (useAsync)
                {
                    StartCoroutine(LoadAndShowTextureAsync(fullPath, canResize));
                }
                else
                {
                    LoadAndShowTexture(fullPath);
                }
            }
            else
            {
                LoadAndPlayVideo(fullPath, autoPlay, playSound, isLoop);
            }
        }

        public void SetVideo(string videoPath, bool canResize = true, bool autoPlay = true, bool playSound = true, Action onPlayEnd = null)
        {
            gameObject.SetActive(true);
            this.canResize = IsFullScreen() ? false : canResize;
            if (onPlayEnd != null) this.onPlayEndAction = onPlayEnd;
            bool isLoop = onPlayEnd == null;
            LoadAndPlayVideo(videoPath, autoPlay, playSound, isLoop);
        }

        public void SetTexture(Texture2D texture, bool canResize = true)
        {
            mediaPlayer.Stop();
            mediaPlayer.enabled = false;
            transform.localEulerAngles = new Vector3(0, 0, 0);
            DestroyAssets();
            if (!rawImage) rawImage = GetComponent<RawImage>() ?? gameObject.AddComponent<RawImage>();
            rawImage.enabled = true;
            rawImage.texture = texture;
            if (!IsFullScreen() && canResize)
            {
                rawImage.SetNativeSize();
            }
            isLoaded = true;
            onLoadedAction?.Invoke();
            onLoaded?.Invoke();
        }

        void LoadAndPlayVideo(string videoPath, bool autoPlay, bool playSound, bool isLoop)
        {
            if (controller) controller.gameObject.SetActive(true);
            this.path = videoPath;
            DestroyAssets();
            displayUGUI = GetComponent<DisplayUGUI>() ?? gameObject.AddComponent<DisplayUGUI>();
            displayUGUI.CurrentMediaPlayer = mediaPlayer;
            mediaPlayer.enabled = true;
            mediaPlayer.m_Loop = isLoop;
            mediaPlayer.m_Volume = playSound ? 1 : 0;
            mediaPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.AbsolutePathOrURL, videoPath, autoPlay);
        }

        void LoadAndShowTexture(string texPath)
        {
            if (controller) controller.gameObject.SetActive(false);
            this.path = texPath;
            mediaPlayer.Stop();
            mediaPlayer.enabled = false;
            transform.localEulerAngles = new Vector3(0, 0, 0);
            DestroyAssets();
            if (!rawImage) rawImage = GetComponent<RawImage>() ?? gameObject.AddComponent<RawImage>();
            rawImage.enabled = true;
            rawImage.texture = LoadTexture(texPath);
            if (canResize)
            {
                rawImage.SetNativeSize();
            }
            isLoaded = true;
            onLoadedAction?.Invoke();
            onLoaded?.Invoke();
        }

        IEnumerator LoadAndShowTextureAsync(string path, bool resize)
        {
            transform.localEulerAngles = new Vector3(0, 0, 0);
            if (File.Exists(path))
            {
                UnityWebRequest request = UnityWebRequestTexture.GetTexture(path);
                DownloadHandlerTexture handlerTexture = new DownloadHandlerTexture(true);
                request.downloadHandler = handlerTexture;
                yield return request.SendWebRequest();
                mediaPlayer.Stop();
                mediaPlayer.enabled = false;
                Texture2D texture = handlerTexture.texture;
                DestroyAssets();
                if (!rawImage) rawImage = GetComponent<RawImage>() ?? gameObject.AddComponent<RawImage>();
                rawImage.enabled = true;
                rawImage.texture = texture;
                if (resize)
                {
                    rawImage.SetNativeSize();
                }
                isLoaded = true;
                onLoadedAction?.Invoke();
                onLoaded?.Invoke();
            }
            else
            {
                Debug.LogError("图片不存在:" + path);
            }
        }

        bool IsFullScreen()
        {
            return rectTransform.anchorMin == Vector2.zero && rectTransform.anchorMax == Vector2.one;
        }

        /// <summary>
        /// 获取本地贴图
        /// </summary>
        public static Texture2D LoadTexture(string path)
        {
            if (!path.EndsWith(".jpg") && !path.EndsWith(".png"))
            {
                if (File.Exists(path + ".jpg"))
                {
                    path += ".jpg";
                }
                else
                {
                    path += ".png";
                }
            }
            return MainController.GetTexture(path);
        }

        /// <summary>
        /// 播放当前加载过的视频
        /// </summary>
        public void PlayVideo(bool seekToBegin, Action onPlayEnd)
        {
            gameObject.SetActive(true);
            if (onPlayEnd != null) this.onPlayEndAction = onPlayEnd;
            mediaPlayer.enabled = true;
            mediaPlayer.m_Loop = onPlayEnd == null;
            if (seekToBegin)
            {
                mediaPlayer.Stop();
            }
            mediaPlayer.Play();
        }

        /// <summary>
        /// 如果视频正在播放则暂停视频
        /// </summary>
        public void PauseVideo()
        {
            mediaPlayer.Pause();
        }

        /// <summary>
        /// 停止视频
        /// </summary>
        public void StopVideo()
        {
            mediaPlayer.Stop();
        }

    }
}